package com.hy.usercenter.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.hy.usercenter.common.ResultEnum;
import com.hy.usercenter.exception.CommonException;
import com.hy.usercenter.model.domain.SysUser;
import com.hy.usercenter.model.request.UserListDto;
import com.hy.usercenter.service.SysUserService;
import com.hy.usercenter.mapper.SysUserMapper;
import com.hy.usercenter.utils.HttpUtils;
import com.hy.usercenter.utils.UserHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import static com.hy.usercenter.constants.UserConstant.*;

/**
 * @author minsf
 * @description 用户服务实现类
 * @createDate 2023-02-08 11:36:05
 */
@Service
@Slf4j
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser>
        implements SysUserService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Transactional
    @Override
    public Long userRegister(String userAccount, String userPassword, String checkPassword) {
        //1、校验(也可以在实体类校验，推荐在这里)
        if (StringUtils.isAllBlank(userAccount, userPassword, checkPassword)) {
            throw new CommonException(ResultEnum.PARAMS_ERROR, "表单必填参数存在空值");
        }
        if (userAccount.length() < 4) {
            throw new CommonException(ResultEnum.PARAMS_ERROR, "账户长度小于4");
        }
        if (userPassword.length() < 8 || checkPassword.length() < 8) {
            throw new CommonException(ResultEnum.PARAMS_ERROR, "密码长度小于8");
        }

        //账户不能有特殊字符，仅能包含字母、数字和下划线
        String pattern = "^[a-zA-Z0-9_]+$";
        boolean matches = userAccount.matches(pattern);
        if (!matches) {
            throw new CommonException(ResultEnum.PARAMS_ERROR, "账户包含了特殊字符");
        }

        if (!userPassword.equals(checkPassword)) {
            throw new CommonException(ResultEnum.PARAMS_ERROR, "两次密码不匹配");
        }

        //用户账户不能重复,放到最后，防止造成性能的浪费
        LambdaQueryWrapper<SysUser> lambdaQueryWrapper = Wrappers.lambdaQuery();
        lambdaQueryWrapper.eq(SysUser::getUserAccount, userAccount);
        long count = this.count(lambdaQueryWrapper);
        if (count > 0) {
            throw new CommonException(ResultEnum.DATABASE_ERROR, "该用户已被注册");
        }

        //2、加密 JAVA包自带的加密工具
        String encryptPassword = DigestUtils.md5DigestAsHex((SALT + userPassword).getBytes(StandardCharsets.UTF_8));

        //插入数据
        SysUser user = new SysUser();
        user.setUserAccount(userAccount);
        user.setUserPassword(encryptPassword);
        user.setUserName("默认用户名，请修改");
        boolean save = this.save(user);

        if (!save) {
            throw new CommonException(ResultEnum.DATABASE_ERROR, "数据库异常，请联系管理员");
        }
        return user.getId();
    }

    @Override
    public SysUser userLogin(String userAccount, String userPassword, HttpServletRequest request) {
        // 1、校验用户登录信息是否合法
        if (StringUtils.isAnyBlank(userAccount, userPassword)) {
            throw new CommonException(ResultEnum.PARAMS_ERROR, "表单必填参数存在空值");
        }
        if (userAccount.length() < 4) {
            throw new CommonException(ResultEnum.PARAMS_ERROR, "账户长度小于4");
        }
        if (userPassword.length() < 8) {
            throw new CommonException(ResultEnum.PARAMS_ERROR, "密码长度小于8");
        }

        //账户不能有特殊字符，仅能包含字母、数字和下划线
        String pattern = "^[a-zA-Z0-9_]+$";
        boolean matches = userAccount.matches(pattern);
        if (!matches) {
            throw new CommonException(ResultEnum.PARAMS_ERROR, "账户包含了特殊字符");
        }

        // 2. 校验密码是否输入正确，要和数据库中的密文密码去对比
        String encryptPassword = DigestUtils.md5DigestAsHex((SALT + userPassword).getBytes(StandardCharsets.UTF_8));
        LambdaQueryWrapper<SysUser> lambdaQueryWrapper = Wrappers.lambdaQuery();
        lambdaQueryWrapper.eq(SysUser::getUserAccount, userAccount);
        SysUser user = Optional.ofNullable(this.getOne(lambdaQueryWrapper)).orElse(new SysUser());
        if (!encryptPassword.equals(user.getUserPassword())) {
            throw new CommonException(ResultEnum.NO_LOGIN, "密码错误!");
        }

        user = maskUser(user);

        HttpSession session = request.getSession();
        session.setAttribute(USER_LOGIN_STATE, user);
        // 30分钟
        session.setMaxInactiveInterval(30 * 60);
        return user;
    }

    @Override
    public Page<SysUser> userList(UserListDto userParam) {
        Page<SysUser> page = new Page<>();
        page.setSize(Optional.ofNullable(userParam.getPageSize()).orElse(5));
        page.setCurrent(Optional.ofNullable(userParam.getCurrent()).orElse(1));

        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(userParam.getUserAccount() != null, SysUser::getUserAccount, userParam.getUserAccount());
        queryWrapper.like(userParam.getPhone() != null, SysUser::getPhone, userParam.getPhone());
        queryWrapper.like(userParam.getUserName() != null, SysUser::getUserName, userParam.getUserName());
        queryWrapper.like(userParam.getEmail() != null, SysUser::getEmail, userParam.getEmail());
        queryWrapper.like(userParam.getGender() != null, SysUser::getGender, userParam.getGender());
        queryWrapper.like(userParam.getUserStatus() != null, SysUser::getUserStatus, userParam.getUserStatus());
        queryWrapper.like(userParam.getUserRole() != null, SysUser::getUserRole, userParam.getUserRole());

        queryWrapper.ge(userParam.getStartTime() != null, SysUser::getCreateTime, userParam.getStartTime());
        queryWrapper.le(userParam.getEndTime() != null, SysUser::getCreateTime, userParam.getEndTime());

        Page<SysUser> userPage = this.page(page, queryWrapper);

        userPage.getRecords().forEach(this::maskUser);
        return userPage;
    }

    @Override
    public SysUser maskUser(SysUser user) {
        if (user == null) {
            throw new CommonException(ResultEnum.NO_LOGIN, "用户信息异常");
        }
        // 3.用户信息脱敏，隐藏敏感信息，防止数据库中的字段泄露
//        String maskPhoneNumber = UserUtils.maskPhoneNumber(user.getPhone());
//        user.setPhone(maskPhoneNumber);
        user.setUserPassword("");
        user.setIsDeleted(null);
        return user;
    }

    @Override
    public List<SysUser> listUserByTags(List<String> tagList) {

        if (CollectionUtils.isEmpty(tagList)) {
            throw new CommonException(ResultEnum.PARAMS_ERROR, "参数不能为空");
        }
        LambdaQueryWrapper<SysUser> queryWrapper = Wrappers.lambdaQuery();

        for (String tagName : tagList) {
            queryWrapper = queryWrapper.like(SysUser::getTags, tagName);
        }
        List<SysUser> list = this.list(queryWrapper);
        list.forEach(this::maskUser);
        return list;
    }

    @Override
    public List<SysUser> listUserByTagsCache(List<String> tagNameList) {
        if (CollectionUtils.isEmpty(tagNameList)) {
            throw new CommonException(ResultEnum.PARAMS_ERROR, "参数不能为空");
        }
        List<SysUser> userList = this.list(null);

        Gson gson = new Gson();

        return userList.stream().filter(user -> {
            String tagsStr = user.getTags();

            if (StringUtils.isBlank(tagsStr)) {
                return false;
            }

            //这个地方不支持直接转换为List<String>
            Set<String> tagsSet = gson.fromJson(tagsStr, new TypeToken<Set<String>>() {
            }.getType());
            tagsSet = Optional.ofNullable(tagsSet).orElse(new HashSet<>());
            // 用户必须要同时拥有这些标签
            for (String tagName : tagNameList) {
                if (!tagsSet.contains(tagName)) return false;
            }
            return true;
        }).collect(Collectors.toList());

    }

    @Override
    public SysUser updateUserInfo(SysUser user, SysUser currentUserInfo) {
        if (user.getId() == null) {
            throw new CommonException(ResultEnum.PARAMS_ERROR);
        }
        //if (user.getUserName() == null && user.getUserAccount() &&)

        SysUser userDb = this.getById(Optional.ofNullable(user.getId()).orElse(-1L));
        if (userDb == null) {
            throw new CommonException(ResultEnum.DATABASE_ERROR);
        }

        // 如果是管理员可以任意修改
        // 如果不是管理员只允许修改自己的信息
        if (!Boolean.TRUE.equals(isAdmin()) && !user.getId().equals(currentUserInfo.getId())) {
            throw new CommonException(ResultEnum.NO_AUTHORITY);
        }

        boolean isModify = this.updateById(user);
        if (isModify) {
            return this.getById(user.getId());
        }

        return null;
    }

    @Override
    public SysUser getCurrentUserInfo() {
        HttpServletRequest request = HttpUtils.getRequest();

        HttpSession session = request.getSession();
        SysUser currentUserInfo = (SysUser) session.getAttribute(USER_LOGIN_STATE);
        if (currentUserInfo == null || !isAdmin()) {
            throw new CommonException(ResultEnum.NO_AUTHORITY);
        }
        return currentUserInfo;
    }

    @Override
    public Boolean isAdmin() {
        HttpServletRequest request = HttpUtils.getRequest();

        HttpSession session = request.getSession();
        SysUser user = (SysUser) session.getAttribute(USER_LOGIN_STATE);
        if (user == null || !user.getUserRole().equals(ADMIN)) {
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }

    /**
     * 使用缓存技术优化查询速度
     *
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public Page<SysUser> listUserIndexByTags(Long pageNum, Long pageSize) {
        ValueOperations<String, Object> operations = redisTemplate.opsForValue();
        SysUser currentUserInfo = UserHelper.getCurrentUserInfo();
        try {

            // 未登录用户、缓存失效、发生异常，直接走数据库
            if (currentUserInfo != null) {

                Page<SysUser> result = (Page<SysUser>) operations.get(KEY_PREFIX + currentUserInfo.getId());

                if (result != null)
                    return result;
            }

        } catch (Exception e) {
            log.error("首页获取缓存发生了错误！");
        }
        // 否则走数据库
        Page<SysUser> page = this.page(new Page<SysUser>(pageNum, pageSize));
        if (page == null) {
            throw new CommonException(ResultEnum.DATABASE_ERROR);
        }
        // 将结果存入缓存
        if (currentUserInfo != null) {
            operations.set(KEY_PREFIX+currentUserInfo.getId(), page);
        }
        return page;
    }

}




